﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IoTCM
{
    public class ThingCollection : IEnumerable<Thing>
    {
        private object m_syncRoot;
        private Dictionary<string, Thing> m_things;
        private Thing m_parent;

        public ThingCollection()
            : this(null)
        {
        }

        internal ThingCollection(Thing parent)
        {
            m_parent = parent;
            // ThingID is case-insensitive
            m_things = new Dictionary<string, Thing>(StringComparer.InvariantCultureIgnoreCase);
            m_syncRoot = new object();
        }

        public int Count
        {
            get { return m_things.Count; }
        }

        public Thing Add(Thing thing)
        {
            if(thing == null) throw new ArgumentNullException();

            lock (m_syncRoot)
            {
                if (m_things.ContainsKey(thing.ID))
                {
                    throw new ArgumentException(string.Format("Thing with ID '{0}' already in collection", thing.ID));
                }

                // TODO: look for ID duplication in children

                m_things.Add(thing.ID, thing);
            }

            return thing;
        }

        public Thing this[string thingID]
        {
            get
            {
                if (string.IsNullOrEmpty(thingID))
                {
                    throw new ArgumentException("thingID is required");
                }

                return m_things[thingID];
            }
        }

        public void AddRange(IEnumerable<Thing> things)
        {
            if (things == null) throw new ArgumentNullException();

            foreach (var thing in things)
            {
                Add(thing);
            }
        }

        public bool Contains(string thingID)
        {
            return m_things.ContainsKey(thingID);
        }

        public Thing Find(string thingID)
        {
            Thing found = null;

            if(m_things.ContainsKey(thingID))
            {
                return m_things[thingID];
            }

            foreach(var thing in this)
            {
                if (thing.HasThings())
                {
                    found = thing.Things.Find(thingID);

                    if (found != null) return found;
                }
            }

            return null;
        }

        public Thing FindValueContainer(string valueID)
        {
            foreach (var thing in this)
            {
                var item = thing.Items[valueID];

                if (item != null)
                {
                    return thing;
                }
                else if(thing.HasThings())
                {
                    return thing.Things.FindValueContainer(valueID);
                }
            }

            return null;
        }

        public IEnumerator<Thing> GetEnumerator()
        {
            lock (m_syncRoot)
            {
                return m_things.Values.GetEnumerator();
            }
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public Thing Thing(string thingID)
        {
            lock (m_syncRoot)
            {
                if (!m_things.ContainsKey(thingID))
                {
                    return null;
                }

                return m_things[thingID];
            }
        }

    }
}
